package org.dayatang.persistence.hibernate;
import org.dayatang.domain.*;
import org.hibernate.query.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.MatchMode;
import org.hibernate.query.NativeQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 通用仓储接口的Hibernate实现。
* <p> EntityRepositoryHibernate通过SessionProvider获取Session,以保证在当前线程和事务中
* 对数据库的多次访问都是由同一个Session来进行,防止出现“会话已关闭”异常。
*
* @author yyang (<a href="mailto:gdyangyu@gmail.com">gdyangyu@gmail.com</a>)
*
*/
@SuppressWarnings({"unchecked"})
public class EntityRepositoryHibernate implements EntityRepository {
private static final Logger LOGGER = LoggerFactory.getLogger(EntityRepositoryHibernate.class);
private final SessionProvider sessionProvider;
public EntityRepositoryHibernate() {
sessionProvider = new SessionProvider();
}
public EntityRepositoryHibernate(SessionFactory sessionFactory) {
this.sessionProvider = new SessionProvider(sessionFactory);
}
public EntityRepositoryHibernate(Session session) {
this.sessionProvider = new SessionProvider(session);
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#save(org.dayatang.domain.Entity)
*/
@Override
public <T extends Entity> T save(T entity) {
getSession().saveOrUpdate(entity);
LOGGER.info("save a entity: " + entity.getClass() + "/" + entity.getId() + ".");
// if (entity.notExisted()) {
// getSession().save(entity);
// LOGGER.info("create a entity: " + entity.getClass() + "/" + entity.getId() + ".");
// return entity;
// }
// getSession().update(entity);
// LOGGER.info("update a entity: " + entity.getClass() + "/" + entity.getId() + ".");
return entity;
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#remove(org.dayatang.domain.Entity)
*/
@Override
public void remove(Entity entity) {
getSession().delete(entity);
LOGGER.info("remove a entity: " + entity.getClass() + "/" + entity.getId() + ".");
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#exists(java.lang.Class, java.io.Serializable)
*/
@Override
public <T extends Entity> boolean exists(final Class<T> clazz, final Serializable id) {
return get(clazz, id) != null;
}
/*
* (non-Javadoc)
*
* @see org.dayatang.domain.EntityRepository#get(java.io.Serializable)
*/
@Override
public <T extends Entity> T get(final Class<T> clazz, final Serializable id) {
return (T) getSession().get(clazz, id);
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#load(java.lang.Class, java.io.Serializable)
*/
@Override
public <T extends Entity> T load(final Class<T> clazz, final Serializable id) {
return (T) getSession().load(clazz, id);
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#getUnmodified(java.lang.Class, org.dayatang.domain.Entity)
*/
@Override
public <T extends Entity> T getUnmodified(Class<T> clazz, T entity) {
getSession().evict(entity);
return get(clazz, entity.getId());
}
@Override
public <T extends Entity> T getByBusinessKeys(Class<T> clazz, NamedParameters keyValues) {
List<T> results = findByProperties(clazz, keyValues);
return results.isEmpty() ? null : results.get(0);
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#findAll(java.lang.Class)
*/
@Override
public <T extends Entity> List<T> findAll(Class<T> clazz) {
return getSession().createCriteria(clazz).list();
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#createCriteriaQuery(java.lang.Class)
*/
@Override
public <T extends Entity> CriteriaQuery createCriteriaQuery(Class<T> entityClass) {
return new CriteriaQuery(this, entityClass);
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#find(org.dayatang.domain.CriteriaQuery)
*/
@SuppressWarnings("rawtypes")
@Override
public <T> List<T> find(CriteriaQuery criteriaQuery) {
Query query = getSession().createQuery(criteriaQuery.getQueryString());
processQuery(query, criteriaQuery.getParameters(),
criteriaQuery.getFirstResult(), criteriaQuery.getMaxResults());
return query.list();
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#getSingleResult(org.dayatang.domain.CriteriaQuery)
*/
@Override
public <T> T getSingleResult(CriteriaQuery criteriaQuery) {
List<T> results = find(criteriaQuery);
return results == null || results.isEmpty() ? null : results.get(0);
}
@Override
public <T extends Entity> List<T> find(Class<T> entityClass, QueryCriterion criterion) {
return find(createCriteriaQuery(entityClass).and(criterion));
}
@Override
public <T extends Entity> T getSingleResult(Class<T> entityClass, QueryCriterion criterion) {
return getSingleResult(createCriteriaQuery(entityClass).and(criterion));
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#createJpqlQuery(java.lang.String)
*/
@Override
public JpqlQuery createJpqlQuery(String jpql) {
return new JpqlQuery(this, jpql);
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#find(org.dayatang.domain.JpqlQuery)
*/
@Override
public <T> List<T> find(JpqlQuery jpqlQuery) {
return getQuery(jpqlQuery).list();
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#getSingleResult(org.dayatang.domain.JpqlQuery)
*/
@Override
public <T> T getSingleResult(JpqlQuery jpqlQuery) {
return (T) getQuery(jpqlQuery).uniqueResult();
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#executeUpdate(org.dayatang.domain.JpqlQuery)
*/
@Override
public int executeUpdate(JpqlQuery jpqlQuery) {
return getQuery(jpqlQuery).executeUpdate();
}
private Query getQuery(JpqlQuery jpqlQuery) {
Query query = getSession().createQuery(jpqlQuery.getJpql());
processQuery(query, jpqlQuery);
return query;
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#createNamedQuery(java.lang.String)
*/
@Override
public NamedQuery createNamedQuery(String queryName) {
return new NamedQuery(this, queryName);
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#find(org.dayatang.domain.NamedQuery)
*/
@Override
public <T> List<T> find(NamedQuery namedQuery) {
return getQuery(namedQuery).list();
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#getSingleResult(org.dayatang.domain.NamedQuery)
*/
@Override
public <T> T getSingleResult(NamedQuery namedQuery) {
return (T) getQuery(namedQuery).uniqueResult();
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#executeUpdate(org.dayatang.domain.NamedQuery)
*/
@Override
public int executeUpdate(NamedQuery namedQuery) {
return getQuery(namedQuery).executeUpdate();
}
private Query getQuery(NamedQuery namedQuery) {
Query query = getSession().getNamedQuery(namedQuery.getQueryName());
processQuery(query, namedQuery);
return query;
}
@Override
public SqlQuery createSqlQuery(String sql) {
return new SqlQuery(this, sql);
}
@SuppressWarnings("rawtypes")
@Override
public <T> List<T> find(SqlQuery sqlQuery) {
return getQuery(sqlQuery).list();
}
@Override
public <T> T getSingleResult(SqlQuery sqlQuery) {
return (T) getQuery(sqlQuery).uniqueResult();
}
@Override
public int executeUpdate(SqlQuery sqlQuery) {
return getQuery(sqlQuery).executeUpdate();
}
private Query getQuery(SqlQuery sqlQuery) {
NativeQuery query = getSession().createNativeQuery(sqlQuery.getSql());
processQuery(query, sqlQuery);
Class resultEntityClass = sqlQuery.getResultEntityClass();
if (resultEntityClass != null) {
query.addEntity(resultEntityClass);
}
return query;
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#findByExample(org.dayatang.domain.Entity, org.dayatang.domain.ExampleSettings)
*/
@Override
public <T extends Entity, E extends T> List<T> findByExample(final E example, final ExampleSettings<T> settings) {
Example theExample = Example.create(example);
if (settings.isLikeEnabled()) {
theExample.enableLike(MatchMode.ANYWHERE);
}
if (settings.isIgnoreCaseEnabled()) {
theExample.ignoreCase();
}
if (settings.isExcludeNone()) {
theExample.excludeNone();
}
if (settings.isExcludeZeroes()) {
theExample.excludeZeroes();
}
for (String propName : settings.getExcludedProperties()) {
theExample.excludeProperty(propName);
}
return getSession().createCriteria(settings.getEntityClass()).add(theExample).list();
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#findByProperty(java.lang.Class, java.lang.String, java.lang.Object)
*/
@Override
public <T extends Entity> List<T> findByProperty(Class<T> clazz, String propertyName, Object propertyValue) {
return find(new CriteriaQuery(this, clazz).eq(propertyName, propertyValue));
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#findByProperties(java.lang.Class, java.util.Map)
*/
@Override
public <T extends Entity> List<T> findByProperties(Class<T> clazz, NamedParameters properties) {
CriteriaQuery criteriaQuery = new CriteriaQuery(this, clazz);
for (Map.Entry<String, Object> each : properties.getParams().entrySet()) {
criteriaQuery = criteriaQuery.eq(each.getKey(), each.getValue());
}
return find(criteriaQuery);
}
@Override
public String getQueryStringOfNamedQuery(String queryName) {
Query query = getSession().getNamedQuery(queryName);
return query.getQueryString();
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#flush()
*/
@Override
public void flush() {
getSession().flush();
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#refresh(org.dayatang.domain.Entity)
*/
@Override
public void refresh(Entity entity) {
getSession().refresh(entity);
}
/*
* (non-Javadoc)
* @see org.dayatang.domain.EntityRepository#clear()
*/
@Override
public void clear() {
getSession().clear();
}
Session getSession() {
return sessionProvider.getSession();
}
private void processQuery(Query query, BaseQuery originQuery) {
processQuery(query, originQuery.getParameters(), originQuery.getFirstResult(),
originQuery.getMaxResults());
fillParameters(query, originQuery.getParameters());
query.setFirstResult(originQuery.getFirstResult());
if (originQuery.getMaxResults() > 0) {
query.setMaxResults(originQuery.getMaxResults());
}
}
private void processQuery(Query query, QueryParameters parameters,
int firstResult, int maxResults) {
fillParameters(query, parameters);
query.setFirstResult(firstResult);
if (maxResults > 0) {
query.setMaxResults(maxResults);
}
}
private void fillParameters(Query query, QueryParameters params) {
if (params == null) {
return;
}
if (params instanceof PositionalParameters) {
fillParameters(query, (PositionalParameters) params);
} else if (params instanceof NamedParameters) {
fillParameters(query, (NamedParameters) params);
} else {
throw new UnsupportedOperationException("不支持的参数形式");
}
}
private void fillParameters(Query query, PositionalParameters params) {
Object[] paramArray = params.getParams();
for (int i = 0; i < paramArray.length; i++) {
query = query.setParameter(i + 1, paramArray[i]);
}
}
private void fillParameters(Query query, NamedParameters params) {
for (Map.Entry<String, Object> entry : params.getParams().entrySet()) {
Object value = entry.getValue();
if (value instanceof Collection) {
query.setParameterList(entry.getKey(), (Collection) value);
} else if (value.getClass().isArray()) {
query.setParameterList(entry.getKey(), (Object[]) value);
} else {
query.setParameter(entry.getKey(), value);
}
}
}
}